會員系統的部分,已經接續完成「會員註冊」、「會員登入」及「修改會員資料」的功能。接續,我們嘗試做做看若會員要「上傳大頭貼」的功能。
form-data
格式的資料。$ npm install formidable
.
├── app.js
├── bin
│ └── www
├── config
│ └── development_config.js
├── controllers
│ └── modify_controller.js
├── models
│ ├── connection_db.js
│ ├── encryption_model.js
│ ├── login_model.js
│ ├── register_model.js
│ ├── update_model.js
│ └── verification_model.js
├── package.json
├── public
│ ├── images
│ ├── javascripts
│ └── stylesheets
│ └── style.css
├── routes
│ ├── member.js
│ └── users.js
├── sevice
│ └── member_check.js
├── views
├── error.ejs
└── index.ejs
├── .env
└── .gitignore
根據需求,我們必須先嘗試讓server端來可以接收圖片,且依據需求中「同一個會員重複上傳不同大頭照只留最新的那張。」這部分就能分三種做法:
「將圖片轉成Base64的格式放置在DB」
「在server端新增一個暫存資料夾並放置」
「使用第三方服務來儲存圖片,並將圖片位置存放在DB」
這部分我們將會使用到formidable
套件。首先,我們先開立另外支API URL給這部分的功能。開啟routes
資料夾的member.js
檔案,修改成:
var express = require('express');
var router = express.Router();
const MemberModifyMethod = require('../controllers/modify_controller');
memberModifyMethod = new MemberModifyMethod();
router.post('/register', memberModifyMethod.postRegister);
router.post('/login', memberModifyMethod.postLogin);
router.put('/update', memberModifyMethod.putUpdate);
router.put('/updateimg', memberModifyMethod.putUpdateImage);
module.exports = router;
接著,我們繼續修改controllers
資料夾的modify_controller.js
檔案,新增一個名為putUpdateImage
的function:
putUpdateImage(req, res, next) {
const form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
res.json({
name: fields.name,
password: fields.password,
file: files.file
})
})
}
讀者可以先找個圖片,檔案大小越小越好。因為在這個階段我們需要透過這個圖片來進行上傳的動作。在找好圖片後,我們使用Postman來進行測試:
註記:
file
就是讀者自己上傳的圖片。
在圖中可以看到所得到的資料分別是我們在Postman上面輸入的key跟value,其中較為特別的是file的部分,透過formidable
套件來幫我們把檔案剖析出來的資料為:
"file": {
"size": 13428,
"path": "/var/folders/q7/nxs9l4lx78bbc_6w5d8wyn5w0000gn/T/upload_5bbd398a624a1331c932b0a311f29789",
"name": "test.jpg",
"type": "image/jpeg",
"mtime": "2018-01-05T11:51:51.275Z"
}
由於在上個步驟發現可以透過formidable
套件來取得檔案的大小及型態,等同於我們可以藉由它來限制只能傳多少kb的檔案及特定副檔名。且需求中也有提到需要我們去定義這部分的規則:
開啟service
資料夾中的member_check.js
檔案,新增兩個規則:
//判斷檔案大小
checkFileSize(fileSize) {
var maxSize = 1 * 1024 * 1024; //1MB
if (fileSize > maxSize) {
return true;
}
return false;
}
//判斷型態是否符合jpg, jpeg, png
checkFileType(fileType) {
if (fileType === 'image/png' || fileType === 'image/jpg' || fileType === 'image/jpeg') {
return true;
}
return false;
}
之後,將這部分的規則加進去controllers
資料夾中的modify_controller
其putUpdateImage
function中。
putUpdateImage(req, res, next) {
const form = new formidable.IncomingForm();
form.parse(req, async function (err, fields, files) {
// 確認檔案大小是否小於1MB
if (check.checkFileSize(files.file.size) === true) {
res.json({
result: {
status: "上傳檔案失敗。",
err: "請上傳小於1MB的檔案"
}
})
return;
}
// 確認檔案型態是否為png, jpg, jpeg
if (check.checkFileType(files.file.type) === true) {
res.json({
name: fields.name,
password: fields.password,
file: files.file
})
} else {
res.json({
result: {
status: "上傳檔案失敗。",
err: "請選擇正確的檔案格式。如:png, jpg, jpeg等。"
}
})
return;
}
})
}
將資料存進去資料庫前,我們還得需要將圖片轉成Base64的格式。而這部分需要Node.js的內置套件fs
來協助我們達成。先額外新增一個function在controllers
資料夾中的modify_controller.js
檔案下:
const fileToBase64 = (filePath) => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'base64', function (err, data) {
resolve(data);
})
})
}
資料庫部分的程式碼,我們已經在昨天完成了。接續我們將該model
加進去controllers
資料夾中的modify_controller.js
。並加入會員登入
部分的功能進去:
putUpdateImage(req, res, next) {
const form = new formidable.IncomingForm();
const token = req.headers['token'];
//確定token是否有輸入
if (check.checkNull(token) === true) {
res.json({
err: "請輸入token!"
})
} else if (check.checkNull(token) === false) {
verify(token).then(tokenResult => {
if (tokenResult === false) {
res.json({
result: {
status: "token錯誤。",
err: "請重新登入。"
}
})
} else {
form.parse(req, async function (err, fields, files) {
// 確認檔案大小是否小於1MB
if (check.checkFileSize(files.file.size) === true) {
res.json({
result: {
status: "上傳檔案失敗。",
err: "請上傳小於1MB的檔案"
}
})
return;
}
// 確認檔案型態是否為png, jpg, jpeg
if (check.checkFileType(files.file.type) === true) {
// 將圖片轉成base64編碼
const image = await fileToBase64(files.file.path);
const id = tokenResult;
// 進行加密
const password = encryption(fields.password);
const memberUpdateData = {
img: image,
name: fields.name,
password: password,
update_date: onTime()
}
updateAction(id, memberUpdateData).then(result => {
res.json({
result: result
})
}, (err) => {
res.json({
result: err
})
})
} else {
res.json({
result: {
status: "上傳檔案失敗。",
err: "請選擇正確的檔案格式。如:png, jpg, jpeg等。"
}
})
return;
}
})
}
})
}
}
修改routes
資料夾的member.js
檔案。
var express = require('express');
var router = express.Router();
const MemberModifyMethod = require('../controllers/modify_controller');
memberModifyMethod = new MemberModifyMethod();
// # Node.js-Backend見聞錄(16):實作-會員系統(五)-添加部分功能更動成:
// 註冊新會員
router.post('/member', memberModifyMethod.postRegister);
// 會員登入
router.post('/member/login', memberModifyMethod.postLogin);
// 更新會員資料
router.put('/member', memberModifyMethod.putUpdate);
// 更新會員資料(檔案上傳示範,可直接取代/member的PUT method)
router.put('/updateimage', memberModifyMethod.putUpdateImage);
module.exports = router;
當前端的夥伴接收到Base64後,其實是可以將它反推成圖片並顯示。使用html中的img
即可:
<img alt="Embedded Image" src="data:image/jpg;base64, /9j/4AAQSkZJRgABAQ... />
會員系統-完整的code
我們終於將會員系統給完成了,不知道讀者在做完該練習後對Node.js的運行及使用方式有沒有多點了解。接續我們將探討如何讓資料庫來進行自動備份。